Copyright ã1995 by NeXT Computer, Inc.  All Rights Reserved.

DBModule

Inherits From:	Object

Declared In:	dbkit/DBModule.h

Class Description

The DBModule class provides the connection between the Database Kit's user interface layer and its access layer.  It does this by letting you associate a set of interface objects with a set of DBRecordLists.  The methods defined by DBModule control the flow of data between the interface objects and the DBRecordLists.  The class also defines a handful of convenience methods that control transactions between a DBModule's ªmainº DBRecordList (the DBRecordList association with the root fetch group, as explained below) and the external database. 

It's strongly recommended that you use Interface Builder to create and instantiate DBModule objects.  (For this, you need the Database Kit palette, described in the section ªDatabase Palette for Interface Builderº in this chapter's introduction.)  Through Interface Builder you can denote the record lists that a DBModule will represent and specify the connections between these record lists and the objects in your application's interface. 

Because of Interface Builder's intercession, you don't need to know much about the DBModule class.  However, you may want to use DBModules to inspect or modify data as it's shuffled between a database and your application's user interface.  For this, you need to know a little bit about how DBModules are built.

Record Lists, Fetch Groups, and Associations

When it's initialized (through initDatabase:entity: method), a DBModule automatically creates two objects:  a DBRecordList, as described by the arguments of the initialization method, and an instance of DBFetchGroup, called the root fetch group.  An instance of DBFetchGroup represents a single DBRecordList and associates it with one or more interface objects; the root fetch group is the object that corresponds to the DBModule's (initial) DBRecordList.  If the DBRecordList contains only one-to-one relationships, then the root fetch group is sufficient for the DBModule.  However, if there are one-to-many relationships in the DBRecordList, additional DBFetchGroups must be created and added to the DBModule, one for each such relationship.  (If you use Interface Builder, the additional DBFetchGroups, if needed, are created and added automatically.)

DBFetchGroups are important not only for the utility that they bring to DBModule, but also because it's through the DBFetchGroup that you can get to a DBModule's DBRecordList objects (which opens the door to the classes in the Database Kit's acces layer).  You can retrieve a DBModule's list of DBFetchGroups through its getFetchGroups: method.

As stated above, a DBFetchGroup contains only one DBRecordList, but can associate that DBRecordList with any number of user interface objects.  Each such association (in other words, each association between an interface object and a DBRecordList) is represented by a DBAssociation object.  It's the DBAssociation's task to take data from the DBRecordList, permute it (if necessary), and send it to the interface object for display.  It must also perform the opposite function, updating the data in the DBRecordList as the user manipulates the data in the interface.  If you're using the standard interface objects supplied by the Database Kit and the Application Kit to display data, then you never need to be aware of the DBAssociations in your application.  However, if you want to use a custom interface objectÐan instance of a class of your own designÐthen that object must implement the DBCustomAssociation informal protocol.  You can retrieve the DBAssociation for a particular interface object through DBModule's associationForObject: method.

Instance Variables

 id database;

 id delegate;

database	The DBDatabase object through which the module is connected to the database

delegate	The object that receives notification messages

Method Types

Initializing a DBModule	- initDatabase:entity:

Querying the DBModule	- database 
- entity 

Accessing fetch groups and associations
- getFetchGroups:
- rootFetchGroup
- fetchGroupNamed:
- addFetchGroup:
- associationForObject:
- editingAssociation

Performing transactions	- fetchContentsOf:usingQualifier:
- fetchAllRecords:
- saveChanges:
- discardChanges:
- deleteRecord:
- appendNewRecord:
- insertNewRecord:

Browsing the record list	- nextRecord:
- previousRecord:

Interface methods	- takeValueFrom:
- textDidEnd:endChar:
- textWillChange:
- textWillEnd:

Accessing the delegate	- setDelegate 
- delegate: 

Instance Methods

addFetchGroup:

- addFetchGroup:aFetchGroup

Adds the given DBFetchGroup object to the list of fetch groups that the DBModule manages.  Returns self.

appendNewRecord:

- appendNewRecord:sender

Creates a new record and adds it to the end of the root fetch group's DBRecordList.  This is a convenience method that's implemented by sending an insertNewRecordAt: message to the root fetch group.  Returns self if the record was successfully appended; otherwise returns nil. 

See also:  - insertNewRecordAt: (DBFetchGroup)

associationForObject:

- associationForObject:anObject

Returns the DBAssociation object that's associated with the given user interface object.

database

- database

Returns the DBDatabase object for which the DBModule was created.

See also:  - initDatabase:entity:

delegate

- delegate

Returns the DBModule's delegate.

See also:  - setDelegate:

deleteRecord:

- deleteRecord:sender

Deletes the currently selected records by sending deleteCurrentSelection to the root fetch group and returns self.

See also:  - deleteCurrentSelection (DBFetchGroup)

discardChanges:

- discardChanges:sender

Terminates any editing changes currently in progress for the DBModule's fetch groups.  The user interface object and the corresponding instance of DBRecordList are cleared in response to this message.  All the DBAssociations involved are notified so that they can update the display accordingly.  The method is implemented by sending a discardChanges message to the DBModule's root fetch group.  Returns self.

editingAssociation

- editingAssociation

Returns the DBAssociation that is currently involved in editing (the one that contains the text insertion cursor).  If none of the DBAssociation objects is involved in editing, returns nil.  

entity

- entity

Returns the DBEntity corresponding to this DBModule.

See also:  - initDatabase:entity:

fetchAllRecords:

- fetchAllRecords:sender

Fetches records into the root fetch group.  This method is implemented by invoking fetchContentsOf:usingQualifier: with aSource and aQualifier both nil.   Returns self, unless the fetch fails.  The fetch will fail if the connection to the database is closed and cannot be reopened, or if any of the fetch groups has unsaved changes that may not be discarded.

fetchContentsOf:usingQualifier:

- fetchContentsOf:aSource usingQualifier:aQualifier

Replaces the records in the current DBRecordList with records fetched from the database.  Any editing in progress for this fetch group is terminated.

The argument aSource may be a DBEntity; it may also be a DBValue that specifies a relationship.  When it specifies a relationship, the DBValue object contains both the key value of a source entity and the target entity to which it is joined; such an object responds YES to an isEntity message. For example, if the DBValue is the value ª10º for the attribute ªDepartment,º the effect is to use ªDepartment = 10º as a key that defines the set of records to be fetched.   If aSource is nil, the DBModule's DBEntity is assumed.

The argument aQualifier is a DBQualifier that further restricts the records that will be fetched.  If aQualifier is nil, there is no further qualification and all records are returned.

If the parent DBModule's delegate responds to fetchGroupWillFetch:, it is notified.  Similarly, after the fetch, if the DBModule's delegate responds to fetchGroupDidFetch:, it is  notified, giving it a chance to set up null values for the DBRecordList.  The various DBAssociations are notified that the contents of their views has changed, so they can redraw themselves.  The current record index is set to 0 (the index of the first record).

Returns self when the fetch is successful, and nil otherwise.  A nil return may arise if the root fetch group has unsaved changes that may not be discarded.

See also:  - fetchContentsOf:usingQualifier: (DBFetchGroup), - isEntity (DBTypes protocol)

fetchGroupNamed:

- fetchGroupNamed:(const char *)aName

Returns the DBFetchGroup whose name matches aName (as declared in the model file or set through the DBFetchGroup method setName:).  If aName is nil, the method returns the root fetch group.  Returns nil if the name isn't found.

getFetchGroups:

- getFetchGroups:(List *)aList

Fills aList with the DBModule's DBFetchGroup objects.  Returns aList.

initDatabase:entity:

- initDatabase:aDatabase entity:anEntity

Initializes an instance of DBModule for the given database and entity, and creates and adds  the object's root fetch group.   Returns self.

insertNewRecord:

- insertNewRecord:sender

Creates a new record and inserts it into the root fetch group's DBRecordList.  This is done by sending an insertNewRecordAt: message to the root fetch group, passing the index of the current record as the argument.  Returns self if the record was successfully inserted; otherwise returns nil. 

See also:  - insertNewRecordAt: (DBFetchGroup)

nextRecord:

- nextRecord:sender

Advances the currently selected record in the root fetch group to the next record in the list.  If there is no currently selected record, does nothing.  Returns self.

previousRecord:

- previousRecord:sender

Moves the current selection back to the previous record.  However, if there is no currently selected record, does nothing.  Returns self.

rootFetchGroup

- rootFetchGroup

Returns the module's one required DBFetchGroup (the first in the list of fetch groups).  

saveChanges:

- saveChanges:sender

Causes all changes made within the module to be saved to the database, by saving all the module's fetch groups.  Returns self, but nil if any error occurred.

Instructs the root DBFetchGroup to save the changes that the user has introduced by editing the module's data display.  Returns self if the changes were successfully saved (or if there were no changes to save).

If the database supports transactions and no other transaction is in progress, the saveChanges: method signals the start of a new transaction before starting the save, and commits the transaction if the save is completed successfully.  Thus all changes within the module are saved as a single transaction (see the DBDatabase methods beginTransaction and commitTransaction).

If for any reason the save could not be carried out, saveChanges: returns nil, and leaves the database unchanged.  There are several reasons a save might be unsuccessful.  Before starting the save, the fetch groups may run a validation check.  The method also notifies the DBModule's delegate by sending it a moduleWillSave message, giving the delegate a chance to interpose its own checks.  When the save has been carried out, the method again notifies the delegate, this time by sending it a moduleDidSave message.  The delegate may still object at this point; if it does, the save is rolled back. 

setDelegate:

- setDelegate: anObject

Makes anObject the delegate of the DBModule instance.   Returns self. 

takeValueFrom:

- takeValueFrom:sender

Notifies the DBModule that the user modified one of the displays (DBImageView, NXBrowser).  The DBModule finds the corresponding DBAssociations and through them their DBFetchGroups and causes the object's new value to be read into the appropriate part of the DBRecordList.  Returns self; however, if sender has no association linking it to the module's DBRecordList, returns nil.

textDidEnd:endChar:

- textDidEnd:textObject endChar:(unsigned short)whyEnd

Called by a DBEditableTextFormatter object when it has relinquished first responder status.  The argument whyEnd identifies the character (Tab, Shift-Tab, or Return) that caused the sender to cease being first responder.  A return of YES permits the change to proceed; a return of NO prevents the change and selects the entire text field.  Your application will not normally need to use this method explicitly.

textWillChange:

- (BOOL)textWillChange:textObject

Called by a DBEditableTextFormatter object when the user first makes a change to an editable field in the display.   A return of YES permits editing to proceed.   Your application will not normally need to use this method explicitly.

textWillEnd:

- (BOOL)textWillEnd:textObject

Called by a DBEditableTextFormatter object when it is about to relinquish first responder status.  A return of YES permits the change to proceed; a return of NO prevents the change and selects the entire text field.  Your application will not normally need to use this method explicitly.

Methods Implemented by the Delegate

moduleDidSave:

- moduleDidSave:module

Called when module has completed a save to the database.

moduleWillLoseChanges:

- (BOOL)moduleWillLoseChanges:module

Called when module is about to discard changes received from the user interface.

moduleWillSave:

- (BOOL)moduleWillSave:module

Called when module is about to save its data to the database.